#include "Application.h"

#include "Client.h"
#include "Car.h"


#include <iostream>
using namespace std;

#define LIST_CARS_TEXT "List cars"
#define ADD_CAR_TEXT "Add car"
#define REMOVE_CAR_TEXT "Remove car"
#define EXIT_TEXT "Exit"

Application::MenuEntry Application::m_menuEntries[] = { 
				{LIST_CARS_OPTION, LIST_CARS_TEXT}
				, {ADD_CAR_OPTION, ADD_CAR_TEXT}
				, {REMOVE_CAR_OPTION, REMOVE_CAR_TEXT}
				, {EXIT_OPTION, EXIT_TEXT} };

uint32_t Application::m_initialPoolSize = 10;
uint32_t Application::m_maxPoolSize = 10;

Application::Application(uint32_t initialPoolSize, uint32_t maxPoolSize) : m_clientPool(initialPoolSize, maxPoolSize)
	, m_carFactory(initialPoolSize, maxPoolSize)
{
}

Application::~Application()
{
	// cleanup
	for(auto it = m_clientCarsMap.begin(); it != m_clientCarsMap.end(); it++) {
		Client &client = *(it->first);
		
		vector<Car*> &carsVector = it->second;
		for(auto it2 = carsVector.begin(); it2 != carsVector.end(); it2++) {
			Car *car = *it2;
			m_carFactory.releaseCar(car);
		}

		m_clientPool.releaseObject(it->first);
	}
}

void Application::addCarFunction()
{
	string clientName;
	string carName;
	Car *car;
	Client *client;
	cout << "Enter client name: "; clientName = this->readWord();
	if ((client = this->getClientByName(clientName)) == NULL) {
		// Client-ul nu exista
		client = m_clientPool.getObject();
		client->setName(clientName);
	}

	cout << "Enter car type: "; car = m_carFactory.getCar(this->readWord());
	cout << "Enter car name: "; car->setName(this->readWord());
	cout << "Enter car Dotari: "; car->setDotari(this->readWord());
	cout << "Enter car Motorizare: "; car->setMotorizare(this->readWord());
	cout << "Enter car Dimensiuni: "; car->setDimensiuni(this->readWord());
	cout << "Enter car Culoare: "; car->setCuloare(this->readWord());
	cout << "Enter car Transmisie: "; car->setTransmisie(this->readWord());

	this->addCar(client, car);
}

void Application::removeCarFunction()
{
	string clientName;
	string carName;
	bool foundCar = false;
	Client *client;
	cout << "Enter client name: "; clientName = this->readWord();
	if ((client = this->getClientByName(clientName)) == NULL) {
		// Client-ul nu exista
		cout << "Couldn't find client.";
		return;
	}

	if (m_clientCarsMap.find(client) == m_clientCarsMap.end()) {
		m_clientCarsMap[client] = vector<Car*>();
	}

	cout << "Enter car name: "; carName = this->readWord();

	vector<Car*> &carsVector = m_clientCarsMap[client];
	for(auto it2 = carsVector.begin(); it2 != carsVector.end(); it2++) {
		Car *currentCar = (*it2);
		if (currentCar->name() == carName) {
			m_carFactory.releaseCar(currentCar);
			carsVector.erase(it2);
			foundCar = true;
			break;
		}
	}

	if (foundCar) {
		cout << "Car deleted." << endl;
	} else {
		cout << "Couldn't find car." << endl;
	}


}

void Application::listCarsFunction()
{
	for(auto it = m_clientCarsMap.begin(); it != m_clientCarsMap.end(); it++) {
		Client &client = *(it->first);
		cout << "Client name: " << client.name() << endl;
		
		vector<Car*> &carsVector = it->second;
		if (carsVector.size())
			cout << "\t" << "Cars:" << endl;
		for(auto it2 = carsVector.begin(); it2 != carsVector.end(); it2++) {
			Car &car = *(*it2);
			cout << "\t" << "\t"  << "Type: " << car.type() << endl;
			cout << "\t" << "\t"  << "Name: " << car.name() << endl;
			cout << "\t" << "\t"  << "Dotari: " << car.dotari() << endl;
			cout << "\t" << "\t"  << "Motorizare: " << car.motorizare() << endl;
			cout << "\t" << "\t"  << "Dimensiuni: " << car.dimensiuni() << endl;
			cout << "\t" << "\t"  << "Culoare: " << car.culoare() << endl;
			cout << "\t" << "\t"  << "Transmisie: " << car.transmisie() << endl;
			cout << endl;
		}
	}
}
void Application::addCar(Client *owner, Car* car)
{
	if (m_clientCarsMap.find(owner) == m_clientCarsMap.end()) {
		m_clientCarsMap[owner] = vector<Car*>();
	}

	vector<Car*> &carVector = m_clientCarsMap[owner];
	carVector.push_back(car);
}

Client* Application::getClientByName(std::string name)
{
	for(auto it = m_clientCarsMap.begin(); it != m_clientCarsMap.end(); it++) {
		Client &client = *(it->first);
		if (client == name) {
			return it->first;
		}
	}

	return NULL;
}

void Application::run()
{
	unsigned int choice;
	
	do {
		printMenu();
		choice = readChoice();
		system("CLS");
		handleChoice(choice);
	} while (choice != MenuOption::EXIT_OPTION);
}

/*
	Utils
*/
unsigned int Application::readInt()
{
	unsigned int i;
	cin >> i;
	return i;
}

const string Application::readWord()
{
	string word;
	cin >> word;
	return word;
}

unsigned int Application::readChoice()
{
	cout << "Your option: ";
	return this->readInt();
}

void Application::printMenu()
{
	cout << "--------------------------------------" << endl;
	cout << "Menu: " << endl;
	for (unsigned int i = 0; i < MenuOption::OPTIONS_NUM; i++) {
		cout << m_menuEntries[i].menuOption << ". " << m_menuEntries[i].description << endl;
	}
}

void Application::handleChoice(unsigned int choice)
{
	switch(choice) {
	case LIST_CARS_OPTION: {
		this->listCarsFunction();
			} break;

	case REMOVE_CAR_OPTION: {
		this->removeCarFunction();
			} break;

	case ADD_CAR_OPTION: {
		this->addCarFunction();
			} break;
	}
}
